﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices.ActiveDirectory;
using System.Net;
using System.Threading.Tasks;

using ADSync.EngineComponents;

namespace ADSync
{
	/// <summary>
	/// Main execution class; Entry point for project;
	/// </summary>
	public class Engine
	{
		#region Properties
		private ConfigurationComponent.EngineConfiguration Configuration
		{
			get;
			set;
		}
		#endregion

		#region Constructors
		public Engine(ConfigurationComponent.EngineConfiguration Configuration)
		{
			this.Configuration = Configuration;
		}
		#endregion

		#region Public Methods
		public void Start()
		{
			//GROUPS
			///Gets global groups distinguishedName
			
			///Gets global groups sidHistory
			//+same loop
			///for given group-sid get group-dn
			///add group-dn to Mapping object
			///Groups result by distinguishedName (glue) into 1 Mapping
			///distinguishedName[new] -> dn(s)[old]
			///distinguishedName[old] -> dn(s)[new]

			Mappings GlobalGroups = new Mappings();

			//ACCOUNTS
			//get qmmSecondary first and get all other on second shot => group only employees with secondary accounts???

			///Gets accounts sAMAaccountName, distinguishedName and objectSid
			///Groups results by sAMAccountName (glue) into Mapping object
			///sAMAccountName -> sid(s);dn(s);

			///Gets for all objectSid(s) from legacy
			///Searches for sidHistory in global domain by legacy objecSid
			///Gets distinguishedName and objectSid
			///Creates 2 Mapping objects
			///sAMAccountName[old] -> dn(s)[new];
			///sAMAccountName[old] -> dn(s)[old];

			///Gets direct legacy memberships for all accounts => distinguishedName(s)
			///Groups result into Mapping object
			///sAMAccountName -> group-dn(s);
			//IDEA1
			///Gets effective legacy memberships for all accounts => objecSid(s)
			//+same loop
			///for given group-sid get group-dn searching via binary CHAIN where user is a member
			///Groups result into Mapping object
			///sAMAccountName -> group-dn(s);

			//for removal
			///Gets direct global memberships for all accounts => distinguishedName(s)
			///Groups result into Mapping object
			///sAMAccountName -> group-dn(s);

			//for addition
			///Gets effective global memberships for all accounts => objecSid(s)
			//+same loop
			///for given group-sid get group-dn
			///Groups result into Mapping object
			///sAMAccountName -> group-dn(s);

			//JOBS
			//for removal
			///Goes through all global account memberships
			///Using sAMAccountName -> group-dn(s) Mapping
			///Compares membership through Group Mapping
			///distinguishedName[new] -> dn(s)[old]
			///with legacy user membership
			///If not entitled for membership create remove transaction

			//for addition
			///Goes through all legacy account memberships
			///Using sAMAccountName -> group-dn(s) Mapping
			///Compares membership through Group Mapping
			///distinguishedName[old] -> dn(s)[new]
			///with global user membership
			///If not a member create add transaction


		}
		#endregion

		#region Private Methods

		/// <summary>
		/// Function retrieves groups with respective mappings
		/// </summary>
		/// <returns></returns>
		private Mappings GetGroupMappings()
		{
			
		}

		/// <summary>
		/// Method retrieves GC servers from list of servers provided
		/// </summary>
		/// <param name="DirectoryContextType"></param>
		/// <param name="PreferedServers"></param>
		/// <returns></returns>
		private IEnumerable<GlobalCatalog> GetPreferedGC( String[] PreferedServers)
		{
			foreach(String ServerFqdn in PreferedServers)
			{
				foreach (IPAddress ServerIPAddress in Dns.GetHostEntry(ServerFqdn).AddressList)
				{ 
					DirectoryContext ServerContext = new DirectoryContext(DirectoryContextType.DirectoryServer, ServerIPAddress.ToString() );
					yield return GlobalCatalog.FindOne(ServerContext);
				}
			}
			//this.GetPreferedGC(DirectoryContextType.DirectoryServer, "")
		}

		/// <summary>
		/// Method retrieves GC servers from forest
		/// </summary>
		/// <param name="PreferedServers"></param>
		/// <returns></returns>
		private IEnumerable<GlobalCatalog> GetPreferedGC(String DomainFqdn)
		{
			DirectoryContext ForestContext = new DirectoryContext(DirectoryContextType.Forest, DomainFqdn);
			foreach(GlobalCatalog GCServer in GlobalCatalog.FindAll(ForestContext))
			{
				yield return GCServer;
			}
		}
		#endregion
	}
}
